<?php
/** errno define:
 * 0,   success
 * 111, parameter not exist
 * 112, parameter invalid
 * 113, image data length more than 2M
 * 116, lack some request headers
 * 117, invalid accesskey or secretkey
 * 118, access fordden for quota limit
 * 119, processing internal error
 * 199, unknown error
 */
class sae_image {
	private static $__accesskey = "";
	private static $__secretkey = "";
	private static $__errno = 0;
	private static $__errmsg = "";
	private static $__img_data = "";
	const baseimgurl = "http://image.sae.sina.com.cn/?";
	const image_limitsize = 2097152;
	
	function __construct($accesskey = "", $secretkey = "", $img_data = "") { // if not call composite, you must set img_data!!
		self::$__accesskey = $accesskey;
		self::$__secretkey = $secretkey;
		if (strlen ( $img_data ) > self::image_limitsize) {
			self::$__errno = 112;
			self::$__errmsg = "image data length more than 2M";
			return false;
		}
		self::$__img_data = $img_data;
	}
	
	public function errmsg() {
		return self::$__errmsg;
	}
	
	public function errno() {
		return self::$__errno;
	}
	
	public function setAuth($accesskey, $secretkey) {
		self::$__accesskey = $accesskey;
		self::$__secretkey = $secretkey;
	}
	
	public function setData($img_data) {
		if (strlen ( $img_data ) > self::image_limitsize) {
			self::$__errno = 112;
			self::$__errmsg = "image data length more than 2M";
			return false;
		}
		self::$__img_data = $img_data;
	}
	
	public function resize($width = 0, $height = 0, $format = "jpg") {
		if (self::imageNull ())
			return false;
		$get = "act=resize&width=$width&height=$height&format=$format";
		$post = array ("imagedata" => self::$__img_data );
		return self::postImgData ( $get, $post );
	}
	
	public function resizeRatio($ratio, $format = "jpg") {
		if (self::imageNull ())
			return false;
		$get = "act=resizeratio&ratio=$ratio&format=$format";
		$post = array ("imagedata" => self::$__img_data );
		return self::postImgData ( $get, $post );
	}
	public function crop($lx, $rx, $by, $ty, $format = "jpg") {
		if (self::imageNull ())
			return false;
		$get = "act=crop&lx=$lx&ty=$ty&rx=$rx&by=$by&format=$format";
		$post = array ("imagedata" => self::$__img_data );
		return self::postImgData ( $get, $post );
	}
	
	public function rotate($degree = 90, $format = "jpg") {
		if (self::imageNull ())
			return false;
		$get = "act=rotate&degree=$degree&format=$format";
		$post = array ("imagedata" => self::$__img_data );
		return self::postImgData ( $get, $post );
	}
	
	public function flip_h($format = "jpg") {
		if (self::imageNull ())
			return false;
		$get = "act=flip_h&format=$format";
		$post = array ("imagedata" => self::$__img_data );
		return self::postImgData ( $get, $post );
	}
	
	public function flip_v($format = "jpg") {
		if (self::imageNull ())
			return false;
		$get = "act=flip_v&format=$format";
		$post = array ("imagedata" => self::$__img_data );
		//$post = urlencode("imagedata=" . self::$__img_data);
		return self::postImgData ( $get, $post );
	}
	
	public function convertFormat($format = "jpg") {
		if (self::imageNull ())
			return false;
		$get = "act=format&format=$format";
		$post = array ("imagedata" => self::$__img_data );
		return self::postImgData ( $get, $post );
	}
	
	public function composite($input, $width, $height, $color = 0, $format = "jpg") {
		$get = "act=composite&width=$width&height=$height&color=$color&format=$format";
		return self::postImgData ( $get, $input );
	}
	
	private static function postImgData($getpara, $post) {
		$url = self::baseimgurl . $getpara;
		$s = curl_init ();
		curl_setopt ( $s, CURLOPT_URL, $url );
		curl_setopt ( $s, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0 );
		curl_setopt ( $s, CURLOPT_TIMEOUT, 15 );
		curl_setopt ( $s, CURLOPT_RETURNTRANSFER, true );
		curl_setopt ( $s, CURLOPT_HEADER, 1 );
		curl_setopt ( $s, CURLINFO_HEADER_OUT, true );
		curl_setopt ( $s, CURLOPT_HTTPHEADER, self::genReqestHeader ( $post ) );
		curl_setopt ( $s, CURLOPT_POST, true );
		curl_setopt ( $s, CURLOPT_POSTFIELDS, $post );
		$ret = curl_exec ( $s );
		// exception handle, if error happens, set errno/errmsg, and return false
		$info = curl_getinfo ( $s );
		//print_r($info);
		//echo 'abab';
		//print_r($ret);
		//echo 'abab';
		if (empty ( $info ['http_code'] )) {
			self::$__errno = 120;
			self::$__errmsg = "image service segment fault";
			return false;
		} else if ($info ['http_code'] != 200) {
			self::$__errno = 121;
			self::$__errmsg = "image service internal error";
			return false;
		} else {
			if ($info ['size_download'] == 0) { // get ImageError header
				$header = substr ( $ret, 0, $info ['header_size'] );
				$imageheader = self::extractCustomHeader ( "ImageError", $header );
				if ($imageheader == false) { // not found ImageError header
					self::$__errno = 199;
					self::$__errmsg = "unknown error";
					return false;
				}
				$err = explode ( ",", $imageheader, 2 );
				self::$__errno = $err [0];
				self::$__errmsg = $err [1];
				return false;
			} else {
				$body = substr ( $ret, - $info ['size_download'] );
				return $body;
			}
		}
		return $ret;
	}
	
	private static function genSignature($content, $secretkey) {
		$sig = base64_encode ( hash_hmac ( 'sha256', $content, $secretkey, true ) );
		return $sig;
	}
	
	private static function genReqestHeader($post) {
		$timestamp = date ( 'Y-m-d H:i:s' );
		$cont1 = "ACCESSKEY" . self::$__accesskey . "TIMESTAMP" . $timestamp;
		$reqhead = array ("TimeStamp: $timestamp", "AccessKey: " . self::$__accesskey, "Signature: " . self::genSignature ( $cont1, self::$__secretkey ) );
		return $reqhead;
	}
	
	private static function extractCustomHeader($key, $header) {
		$pattern = '/' . $key . '(.*?)' . "\n/";
		if (preg_match ( $pattern, $header, $result )) {
			return $result [1];
		} else {
			return false;
		}
	}
	
	private static function imageNull() {
		if (self::$__img_data == "") {
			self::$__errno = 112;
			self::$__errmsg = "image data cannot be null";
			return true;
		}
		return false;
	}
}